package com.vision.util.http.down;

import com.google.common.io.Files;
import com.google.common.net.MediaType;
import com.vision.util.http.exception.FileTypeException;
import com.vision.util.http.exception.HttpStatusException;
import com.vision.util.http.util.HttpRequestDao;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.Asserts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StreamUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * @author zhongchao
 * @title
 * @date 2017-08-16
 * @since v1.0.0
 */
public class DownUtil {
    private static final Logger logger = LoggerFactory.getLogger(DownUtil.class);

    private static final String DOWNING_FILE_TYPE = ".downing";


    public static void down(String dest, String src, String fileName, MediaType mediaType, HttpRequestDao httpRequestDao) throws IOException, FileTypeException, HttpStatusException {
        validate(dest, src);
        Asserts.notNull(httpRequestDao, "httpClient 构建不能为空");
        try (CloseableHttpResponse response = httpRequestDao.getResponse(src);) {
            startDown(dest, src, mediaType == null ? MediaType.ANY_TYPE : mediaType, fileName, response);
        }
    }

    private static void validate(String dest, String src) {
        Asserts.notBlank(dest, "下载地址不能为空");
        Asserts.notBlank(src, "下源不能为空");
    }

    public static void down(String dest, String src) throws IOException, FileTypeException, HttpStatusException {
        validate(dest, src);
        try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
            HttpGet httpget = new HttpGet(src);
            try (CloseableHttpResponse response = httpclient.execute(httpget)) {
                startDown(dest, src, MediaType.ANY_TYPE, null, response);
            }
        }
    }

    public static void down(String dest, String src, String fileName, MediaType mediaType) throws IOException, FileTypeException, HttpStatusException {
        validate(dest, src);
        try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
            HttpGet httpget = new HttpGet(src);
            try (CloseableHttpResponse response = httpclient.execute(httpget)) {
                startDown(dest, src, mediaType == null ? MediaType.ANY_TYPE : mediaType, fileName, response);
            }
        }
    }

    private static void startDown(String dest, String src, MediaType mediaType, String fileName, CloseableHttpResponse response) throws FileTypeException, IOException, HttpStatusException {
        int statusCode = response.getStatusLine().getStatusCode();
        HttpEntity entity = response.getEntity();
        Header contentType = entity.getContentType();
        String contentTypeValue = contentType.getValue();
        if (!MediaType.parse(contentTypeValue).is(mediaType)) {
            throw new FileTypeException("准备下载的文件类型错误:" + contentTypeValue);
        }
        if (statusCode == HttpStatus.SC_OK) {
            generateFile(entity, dest, genFileName(src, fileName, contentTypeValue));
        } else {
            throw new HttpStatusException("下载失败! url:" + src + " status:" + statusCode);
        }
    }

    private static String genFileName(String src, String fileName, String contentTypeValue) {
        String end = typeToName(contentTypeValue);
        if (fileName == null) {
            if (src.endsWith("/")) {
                src = src.substring(0, src.length() - 1);
            }
            fileName = src.substring(StringUtils.lastIndexOf(src, "/") + 1, src.length());
            int i = StringUtils.lastIndexOf(fileName, ".");
            if (i > -1) {
                fileName = fileName.substring(0, i);
            }
        }
        return fileName + end;
    }

    private static void generateFile(HttpEntity entity, String dest, String fileName) throws IOException {
        try (InputStream content = entity.getContent()) {
            String downingName = fileName + DOWNING_FILE_TYPE;
            File file = new File(dest, downingName);
            File realFile = new File(dest, fileName);
            if (realFile.exists()) {
                logger.warn("存在文件 直接跳过下载... 文件名称:{}", realFile.getName());
                return;
            }
            Files.createParentDirs(file);
            try (FileOutputStream outputStream = new FileOutputStream(file, true)) {
                StreamUtils.copy(content, outputStream);
                logger.info("文件下载完成:{}", realFile.getName());
            }
            renameFile(file, realFile);

        }
    }

    /**
     * 重命名文件
     *
     * @param oldFile 原文件
     * @param newFile 新文件
     */
    private static void renameFile(File oldFile, File newFile) {
        //设置文件结束
        try {
            Files.move(oldFile, newFile);
        } catch (IOException e) {
            logger.info("重命名文件失败:源文件名称:{}", oldFile.getName());
        }

    }

    private static String typeToName(String contentTypeValue) {
        String end = "";
        MediaType parse = MediaType.parse(contentTypeValue);
        if (parse.is(MediaType.ANY_VIDEO_TYPE)) {
            end = ".mp4";
        } else if (parse.is(MediaType.ANY_AUDIO_TYPE)) {
            end = ".mp4";
        } else if (parse.is(MediaType.ANY_IMAGE_TYPE)) {
            end = ".jpg";
        } else if (parse.is(MediaType.ANY_TEXT_TYPE)) {
            end = ".txt";
        } else {
            end = ".unknow";
        }
        return end;
    }

    public static void main(String[] args) throws HttpStatusException, FileTypeException, IOException {
        DownUtil.down("e://", "http://www.importnew.com/wp-content/uploads/2014/12/6c537425c9ad078efe656a346e5facec.png", null, MediaType.ANY_TYPE);

    }
}
